BigQuery へのアクセスを IAM Conditions とタグで制御する方法のまとめ
Google Cloud データエンジニアのはんざわです。
過去のブログで BigQuery のデータセットへのアクセスをタグで制御する方法を紹介しました。
本ブログでは、過去のブログで紹介しきれなかった内容をまとめて紹介したいと思います。
具体的には、タグでアクセスを制御する関数の紹介やアクセス制御の挙動の確認、ユースケースについて触れていきます。
また、前回のブログを投稿した時は、タグを使用した BigQuery のテーブルへのアクセス制限の機能はプレビューでしたが、2024年6月27日に正式に GA になっています。
本機能も併せて紹介したいと思います。
You can now use tags on BigQuery tables to conditionally grant or deny access with Identity and Access Management (IAM) policies. This feature is generally available (GA). You can also attach tags to BigQuery datasets during dataset creation to conditionally grant or deny access with IAM policies.
IAM Conditions とタグでアクセスを制御する方法
IAM Conditions とタグでアクセスを制御する場合、大きく分けて2つの関数で条件を設定することができます。
- 指定したキーのタグが付いているかどうか
- 指定したキーとバリューのタグが付いているかどうか
IAM Conditionsでは、設定した条件が true
と評価されると、アクセスが許可されます。
また、それぞれの関数は以下のとおりで、IAM Conditions の条件エディタで使用することができます。
# 1
resource.hasTagKey(
keyName: string
) trending_flat -> bool
# 2
resource.matchTag(
keyName: string,
valueShortName: string
) trending_flat -> bool
例として、env
というキーが存在し、そのキーに dev
と prod
という値が設定されていると仮定します。
バリューに関係なく、 env
のキーが付いている全てのリソースを対象としたい場合は、前者の resource.hasTagKey
が使用できます。
一方で、キーが env
で、且つバリューが dev
のリソースを対象としたい場合は、後者の resource.matchTag
が使用できます。
また、タグのキーとバリューには、作成時に一意の ID が割り当てられます。
略称だけでなく、この ID で条件を設定することも可能で、関数は以下になります。
# 1
resource.hasTagKeyId(
keyName: string
) trending_flat -> bool
# 2
resource.matchTagId(
keyName: string,
valueShortName: string
) trending_flat -> bool
参考元:リソースタグ
検証内容
今回の検証内容は、クエリを発行するサービスアカウントに IAM Conditions で条件を付与し、そのサービスアカウントが各操作を行った際の挙動を確認してみたいと思います。
条件
- 特定のキーのダグが付与されているリソースのみ許可
- 特定のキーのダグが付与されていないリソースのみ許可
- 特定のキーとバリューのタグが付与されているリソースのみ許可
- 特定のキーとバリューのタグが付与されていないリソースのみ許可
操作
bq ls
でデータセットが表示されるかbq ls 許可されたデータセット
でテーブルが表示されるかbq ls 許可されていないデータセット
でテーブルが表示されるかbq query 許可されたデータセットの許可されたテーブル
にクエリを発行できるかbq query 許可されたデータセットの許可されていないテーブル
にクエリを発行できるかbq query 許可されていないデータセットの許可されたテーブル
にクエリを発行できるかbq query 許可されていないデータセットの許可されていないテーブル
にクエリを発行できるか
まとめると次の表のようになります。
- bq ls
bq ls |
bq ls 許可されたデータセット |
bq ls 許可されていないデータセット |
|
---|---|---|---|
特定のキーのダグが付与されているリソースのみ許可 | |||
特定のキーのダグが付与されていないリソースのみ許可 | |||
特定のキーとバリューのタグが付与されているリソースのみ許可 | |||
特定のキーとバリューのタグが付与されていないリソースのみ許可 |
- bq query
許可されたデータセットの許可されたテーブル | 許可されたデータセットの許可されていないテーブル | 許可されていないデータセットの許可されたテーブル | 許可されていないデータセットの許可されていないテーブル | |
---|---|---|---|---|
特定のキーのダグが付与されているリソースのみ許可 | ||||
特定のキーのダグが付与されていないリソースのみ許可 | ||||
特定のキーとバリューのタグが付与されているリソースのみ許可 | ||||
特定のキーとバリューのタグが付与されていないリソースのみ許可 |
事前準備
早速、検証に必要なリソースを作成します。
1. タグの作成
1つのキーに1つのバリューが紐づいている2つのタグをプロジェクトレベルで作成します。
今回の例だと、team
と env
がキーで da
と dev
がバリューに相当します。
-
team
da
-
env
dev
2. サービスアカウントの作成
各条件ごとに4つのサービスアカウントを作成します。
それぞれのアカウントに BigQuery ジョブユーザー
と BigQuery データ閲覧者
の権限をプロジェクトレベルで割り当ててます。
sa-team-allowed@<PROJECT_ID>.iam.gserviceaccount.com
- 特定のキーのダグが付与されているリソースにのみ許可
sa-team-denied@<PROJECT_ID>.iam.gserviceaccount.com
- 特定のキーのダグが付与されていないリソースにのみ許可
sa-team-da-allowed@<PROJECT_ID>.iam.gserviceaccount.com
- 特定のキーとバリューのタグが付与されているリソースにのみ許可
sa-team-da-denied@<PROJECT_ID>.iam.gserviceaccount.com
- 特定のキーとバリューのタグが付与されていないリソースのみ許可
3. IAM Conditions で条件を付与
4つのサービスアカウントの BigQuery データ閲覧者
の権限に IAM Conditions で条件を付与していきます。
IAM Conditions の条件エディタで、以下の条件式を追記します。
resource.hasTagKey("<PROJECT_ID>/team")
!resource.hasTagKey("<PROJECT_ID>/team")
resource.matchTag("<PROJECT_ID>/team", "da")
!resource.matchTag("<PROJECT_ID>/team", "da")
参考:条件の CEL
4. データセットとテーブルの作成
3つのデータセットとその配下に適当なテーブルを作成します。
2つのデータセットには、da
と ml
のタグを付与します。
残り1つのデータセットには、タグを付与せず、その配下のテーブルにタグを付与します。
- データセット:
team_da_dataset
-team/da
- テーブル:
sample_table
- テーブル:
sample_table_da
-team/da
- テーブル:
sample_table_dev
-env/dev
- テーブル:
- データセット:
team_dataset
- テーブル:
sample_table
- テーブル:
sample_table_da
-team/da
- テーブル:
sample_table_dev
-env/dev
- テーブル:
検証
ここからは、用意したリソースを使って検証を進めたいと思います。
検証の結果
先に検証の結果から紹介すると、以下の図のようになりました。
- bq ls
bq ls |
bq ls 許可されたデータセット |
bq ls 許可されていないデータセット |
|
---|---|---|---|
特定のキーのダグが付与されているリソースのみ許可 | タグが付与されているデータセット | タグが付与されていないテーブルを含む全てのテーブル | × |
特定のキーのダグが付与されていないリソースのみ許可 | タグが付与されていないデータセット | タグが付与されていないテーブルを含む全てのテーブル | × |
特定のキーとバリューのタグが付与されているリソースのみ許可 | タグが付与されているデータセット | タグが付与されていないテーブルを含む全てのテーブル | × |
特定のキーとバリューのタグが付与されていないリソースのみ許可 | タグが付与されていないデータセット | タグが付与されていないテーブルを含む全てのテーブル | × |
- bq query
許可されたデータセットの許可されたテーブル | 許可されたデータセットの許可されていないテーブル | 許可されていないデータセットの許可されたテーブル | 許可されていないデータセットの許可されていないテーブル | |
---|---|---|---|---|
特定のキーのダグが付与されているリソースのみ許可 | ○ | ○ | ○ | × |
特定のキーのダグが付与されていないリソースのみ許可 | ○ | × | × | × |
特定のキーとバリューのタグが付与されているリソースのみ許可 | ○ | ○ | ○ | × |
特定のキーとバリューのタグが付与されていないリソースのみ許可 | ○ | × | × | × |
考察
resource.hasTagKey
とresource.matchTag
の関数の評価における挙動に違いは無いと思われる(適用範囲がキーだけか、キーとバリューかの違いだけ)- 肯定の関数では、データセットへのアクセスが可能であれば、その配下のテーブルへのアクセスは可能であった
- さらに、データセットへのアクセスが不可能でも、その配下のテーブルへのアクセスが可能であればアクセスすることができた
- 否定の関数では、条件となった特定のタグが付いているリソースにアクセスすることは、完全に不可能であった
- 肯定の関数では可能であったが、否定の関数では、データセットへのアクセスが不可能だと、その配下のテーブルへのアクセスも不可能である
検証の過程
以下のブログで紹介したように、サービスアカウントの権限を借用して、各コマンドを実行してみます。
1. 特定のキーのダグが付与されているリソースのみ許可
# bq ls でデータセットが表示されるか
$ bq ls
> datasetId
-----------------
team_da_dataset
# bq ls 許可されたデータセット でテーブルが表示されるか
$ bq ls team_da_dataset
> tableId Type Labels Time Partitioning Clustered Fields
------------------ ------- -------- ------------------- ------------------
sample_table TABLE
sample_table_da TABLE
sample_table_dev TABLE
# bq ls 許可されていないデータセット でテーブルが表示されるか
$ bq ls team_dataset
> BigQuery error in ls operation: Access Denied: Dataset <PROJECT_ID>:team_dataset: Permission bigquery.tables.list denied on dataset <PROJECT_ID>:team_dataset (or it may not exist).
# bq query 許可されたデータセットの許可されたテーブル にクエリを発行できるか
$ bq query --nouse_legacy_sql 'SELECT COUNT(*) FROM team_da_dataset.sample_table_da'
>
+-----+
| f0_ |
+-----+
| 1 |
+-----+
# bq query 許可されたデータセットの許可されていないテーブル にクエリを発行できるか
$ bq query --nouse_legacy_sql 'SELECT COUNT(*) FROM team_da_dataset.sample_table_dev'
>
+-----+
| f0_ |
+-----+
| 1 |
+-----+
# bq query 許可されていないデータセットの許可されたテーブル
$ bq query --nouse_legacy_sql 'SELECT COUNT(*) FROM team_dataset.sample_table_da'
>
+-----+
| f0_ |
+-----+
| 1 |
+-----+
# bq query 許可されていないデータセットの許可されていないテーブル
bq query --nouse_legacy_sql 'SELECT COUNT(*) FROM team_dataset.sample_table_dev'
> BigQuery error in query operation: Error processing job '<PROJECT_ID>:bqjob_r2abc821e0c5a8ad6_000001927a806441_1': Access Denied: Table <PROJECT_ID>:team_dataset.sample_table_dev: User
does not have permission to query table <PROJECT_ID>:team_dataset.sample_table_dev, or perhaps it does not exist.
2. 特定のキーのダグが付与されていないリソースのみ許可
# bq ls でデータセットが表示されるか
$ bq ls
> datasetId
--------------
team_dataset
# bq ls 許可されたデータセット でテーブルが表示されるか
$ bq ls team_dataset
> tableId Type Labels Time Partitioning Clustered Fields
------------------ ------- -------- ------------------- ------------------
sample_table TABLE
sample_table_da TABLE
sample_table_dev TABLE
# bq ls 許可されていないデータセット でテーブルが表示されるか
$ bq ls team_da_dataset
> BigQuery error in ls operation: Access Denied: Dataset <PROJECT_ID>:team_da_dataset: Permission bigquery.tables.list denied on dataset <PROJECT_ID>:team_da_dataset (or it may not exist).
# bq query 許可されたデータセットの許可されたテーブル にクエリを発行できるか
$ bq query --nouse_legacy_sql 'SELECT COUNT(*) FROM team_dataset.sample_table_dev'
>
+-----+
| f0_ |
+-----+
| 1 |
+-----+
# bq query 許可されたデータセットの許可されていないテーブル にクエリを発行できるか
$ bq query --nouse_legacy_sql 'SELECT COUNT(*) FROM team_dataset.sample_table_da'
> BigQuery error in query operation: Error processing job '<PROJECT_ID>:bqjob_r664a24b76e13da83_000001927a93601f_1': Access Denied: Table <PROJECT_ID>:team_dataset.sample_table_da: User does
not have permission to query table <PROJECT_ID>:team_dataset.sample_table_da, or perhaps it does not exist.
# bq query 許可されていないデータセットの許可されたテーブル
$ bq query --nouse_legacy_sql 'SELECT COUNT(*) FROM team_da_dataset.sample_table_dev'
> BigQuery error in query operation: Error processing job '<PROJECT_ID>:bqjob_r42255aa28a146d11_000001927a9f52ae_1': Access Denied: Table <PROJECT_ID>:team_da_dataset.sample_table_dev: User
does not have permission to query table <PROJECT_ID>:team_da_dataset.sample_table_dev, or perhaps it does not exist.
# bq query 許可されていないデータセットの許可されていないテーブル
bq query --nouse_legacy_sql 'SELECT COUNT(*) FROM team_da_dataset.sample_table_da'
> BigQuery error in query operation: Error processing job '<PROJECT_ID>:bqjob_r7b3a7b2c6bbcef44_000001927aa05bb7_1': Access Denied: Table <PROJECT_ID>:team_da_dataset.sample_table_da: User
does not have permission to query table <PROJECT_ID>:team_da_dataset.sample_table_da, or perhaps it does not exist.
3. 特定のキーとバリューのタグが付与されているリソースのみ許可
# bq ls でデータセットが表示されるか
$ bq ls
> datasetId
-----------------
team_da_dataset
# bq ls 許可されたデータセット でテーブルが表示されるか
$ bq ls team_da_dataset
> tableId Type Labels Time Partitioning Clustered Fields
------------------ ------- -------- ------------------- ------------------
sample_table TABLE
sample_table_da TABLE
sample_table_dev TABLE
# bq ls 許可されていないデータセット でテーブルが表示されるか
$ bq ls team_dataset
> BigQuery error in ls operation: Access Denied: Dataset <PROJECT_ID>:team_dataset: Permission bigquery.tables.list denied on dataset <PROJECT_ID>:team_dataset (or it may not exist).
# bq query 許可されたデータセットの許可されたテーブル にクエリを発行できるか
$ bq query --nouse_legacy_sql 'SELECT COUNT(*) FROM team_da_dataset.sample_table_da'
>
+-----+
| f0_ |
+-----+
| 1 |
+-----+
# bq query 許可されたデータセットの許可されていないテーブル にクエリを発行できるか
$ bq query --nouse_legacy_sql 'SELECT COUNT(*) FROM team_da_dataset.sample_table_dev'
>
+-----+
| f0_ |
+-----+
| 1 |
+-----+
# bq query 許可されていないデータセットの許可されたテーブル
$ bq query --nouse_legacy_sql 'SELECT COUNT(*) FROM team_dataset.sample_table_da'
>
+-----+
| f0_ |
+-----+
| 1 |
+-----+
# bq query 許可されていないデータセットの許可されていないテーブル
bq query --nouse_legacy_sql 'SELECT COUNT(*) FROM team_dataset.sample_table_dev'
> BigQuery error in query operation: Error processing job '<PROJECT_ID>:bqjob_r56a6ec73791ca899_000001927ab4da88_1': Access Denied: Table <PROJECT_ID>:team_dataset.sample_table_dev: User
does not have permission to query table <PROJECT_ID>:team_dataset.sample_table_dev, or perhaps it does not exist.
4. 特定のキーとバリューのタグが付与されていないリソースのみ許可
# bq ls でデータセットが表示されるか
$ bq ls
> datasetId
--------------
team_dataset
# bq ls 許可されたデータセット でテーブルが表示されるか
$ bq ls team_dataset
> tableId Type Labels Time Partitioning Clustered Fields
------------------ ------- -------- ------------------- ------------------
sample_table TABLE
sample_table_da TABLE
sample_table_dev TABLE
# bq ls 許可されていないデータセット でテーブルが表示されるか
$ bq ls team_da_dataset
> BigQuery error in ls operation: Access Denied: Dataset <PROJECT_ID>:team_da_dataset: Permission bigquery.tables.list denied on dataset <PROJECT_ID>:team_da_dataset (or it may not exist).
# bq query 許可されたデータセットの許可されたテーブル にクエリを発行できるか
$ bq query --nouse_legacy_sql 'SELECT COUNT(*) FROM team_dataset.sample_table_dev'
>
+-----+
| f0_ |
+-----+
| 1 |
+-----+
# bq query 許可されたデータセットの許可されていないテーブル にクエリを発行できるか
$ bq query --nouse_legacy_sql 'SELECT COUNT(*) FROM team_dataset.sample_table_da'
> BigQuery error in query operation: Error processing job '<PROJECT_ID>:bqjob_r58e434e7d893788d_000001927abbf9bb_1': Access Denied: Table <PROJECT_ID>:team_dataset.sample_table_da: User does
not have permission to query table <PROJECT_ID>:team_dataset.sample_table_da, or perhaps it does not exist.
# bq query 許可されていないデータセットの許可されたテーブル
$ bq query --nouse_legacy_sql 'SELECT COUNT(*) FROM team_da_dataset.sample_table_dev'
> BigQuery error in query operation: Error processing job '<PROJECT_ID>:bqjob_r1220037fa25add24_000001927abde560_1': Access Denied: Table <PROJECT_ID>:team_da_dataset.sample_table_dev: User
does not have permission to query table <PROJECT_ID>:team_da_dataset.sample_table_dev, or perhaps it does not exist.
# bq query 許可されていないデータセットの許可されていないテーブル
bq query --nouse_legacy_sql 'SELECT COUNT(*) FROM team_da_dataset.sample_table_da'
> BigQuery error in query operation: Error processing job '<PROJECT_ID>:bqjob_r77f0d197698c834c_000001927abe76db_1': Access Denied: Table <PROJECT_ID>:team_da_dataset.sample_table_da: User
does not have permission to query table <PROJECT_ID>:team_da_dataset.sample_table_da, or perhaps it does not exist.
ユースケース
-
大前提として、データの利用者側でデータの閲覧に制限がかかる恐れがあるユーザーには、プロジェクトレベルで
BigQuery データ閲覧者
の権限を割り当てないようにしましょう。 -
データセットレベルで権限を割り当てたり、利用者の集合毎にプロジェクトを切り離したりすることで必要最低限のデータのみを閲覧できるようにしましょう。
-
その上で、次のような条件に当てはまる場合は、タグによるアクセス制御の選択肢も考えられると思います。
- どうしてもプロジェクトレベルで
BigQuery データ閲覧者
の権限を割り当てる必要があるが、特定のデータは閲覧できないようにしたい - 既にプロジェクトレベルで
BigQuery データ閲覧者
の権限を割り当てているが、特定のデータを閲覧できないようにしたい。また、扱っているデータが多いため、権限の振り直しが非常に手間である
- どうしてもプロジェクトレベルで
-
しかし、タグとタグに関する権限を管理する必要が出てくるので、利用には気をつけましょう。
まとめ
今回のブログでは、BigQuery へのアクセスを IAM Conditions とタグで制御する方法をまとめて紹介しました。
非常に長い内容となりましたが、参考になれば幸いです。